
#include "omp/HandEvaluator.h"
#include "omp/EquityCalculator.h"
#include "omp/Random.h"
#include "ttest/ttest.h"
#include "omp/WeightedCardRange.h"
#include "omp/json.hpp"
#include <iostream>
#include <iomanip>
#include <unordered_set>
#include <unordered_map>
#include <vector>
#include <list>
#include <numeric>
#include <set>
#include <cmath>
#include <array>
#include <cstdint>

// 辅助函数声明：将手牌字符串转换为卡牌ID数组
std::array<uint8_t, 2> stringToHand(const std::string& handStr);

// 全局变量存储命令行参数
std::string w_board;
std::string range0;
std::string range1;
std::string range2;

using namespace std;
using namespace omp;
using json = nlohmann::json;

class UtilTest : public ttest::TestBase
{
    TTEST_CASE("countLeadingZeros")
    {
        TTEST_EQUAL(countLeadingZeros(1u), 31u);
        TTEST_EQUAL(countLeadingZeros(0xf0u), 24u);
        TTEST_EQUAL(countLeadingZeros(~0u), 0u);
    }

    TTEST_CASE("countTrailingZeros")
    {
        TTEST_EQUAL(countTrailingZeros((uint32_t)1), 0u);
        TTEST_EQUAL(countTrailingZeros((uint32_t)0x0f000000), 24u);
        TTEST_EQUAL(countTrailingZeros((uint32_t)~0u), 0u);
    }

    TTEST_CASE("bitCount")
    {
        TTEST_EQUAL(bitCount(~0u), sizeof(unsigned) * CHAR_BIT);
        TTEST_EQUAL(bitCount(0xf0u), 4u);
        TTEST_EQUAL(bitCount(~0ul), sizeof(unsigned long) * CHAR_BIT);
        TTEST_EQUAL(bitCount(0xf0ul), 4u);
        TTEST_EQUAL(bitCount(~0ull), sizeof(unsigned long long) * CHAR_BIT);
        TTEST_EQUAL(bitCount(0x0ff00000000000f0ull), 12u);
    }

    TTEST_CASE("alignedNew")
    {
        char* p = (char*)alignedNew(1, 512);
        TTEST_EQUAL((uintptr_t)p % 512, 0u);
        alignedDelete(p);
    }
};

class HandTest : public ttest::TestBase
{
    #if OMP_SSE2
    TTEST_CASE("has 16-byte alignment and size")
    {
        TTEST_EQUAL(OMP_ALIGNOF(Hand), 16u);
        TTEST_EQUAL(sizeof(Hand), 16u);
    }

    TTEST_CASE("allocated objects are aligned")
    {
        struct HandHash
        {
            size_t operator()(const Hand& h) const
            {
                return h.rankKey();
            }
        };

        Hand h;
        TTEST_EQUAL((uintptr_t)&h % sizeof(Hand), 0u);

        vector<Hand> v;
        unordered_set<Hand, HandHash> s;
        unordered_map<Hand,Hand,HandHash> m;
        list<Hand> l;
        for (unsigned i = 0; i < 52; ++i) {
            TTEST_EQUAL((uintptr_t)&*v.insert(v.end(), i) % sizeof(Hand), 0u);
            TTEST_EQUAL((uintptr_t)&*s.insert(i).first % sizeof(Hand), 0u);
            TTEST_EQUAL((uintptr_t)&(m[i] = Hand(i)) % sizeof(Hand), 0u);
            TTEST_EQUAL((uintptr_t)&*l.insert(l.end(), i) % sizeof(Hand), 0u);
        }
    }
    #endif

    TTEST_CASE("empty()")
    {
        Hand h = Hand::empty();
        TTEST_EQUAL(h.count(), 0u);
        TTEST_EQUAL(h.suitCount(0), 0u);
    }

    TTEST_CASE("adding & removing cards")
    {
        Hand h = Hand::empty() + Hand(5);
        TTEST_EQUAL(h.count(), 1u);
        TTEST_EQUAL(h.suitCount(1), 1u);
        h += Hand(51);
        TTEST_EQUAL(h.count(), 2u);
        TTEST_EQUAL(h.suitCount(0), 0u);
        TTEST_EQUAL(h.suitCount(1), 1u);
        TTEST_EQUAL(h.suitCount(3), 1u);
        h += Hand(3);
        TTEST_EQUAL(h.count(), 3u);
        TTEST_EQUAL(h.suitCount(0), 0u);
        TTEST_EQUAL(h.suitCount(1), 1u);
        TTEST_EQUAL(h.suitCount(3), 2u);
        h -= Hand(51);
        TTEST_EQUAL(h.count(), 2u);
        TTEST_EQUAL(h.suitCount(0), 0u);
        TTEST_EQUAL(h.suitCount(1), 1u);
        TTEST_EQUAL(h.suitCount(3), 1u);
        h = h - (Hand(3) + Hand(5));
        TTEST_EQUAL(h.count(), 0u);
    }

    TTEST_CASE("flush check")
    {
        Hand h = Hand::empty();
        TTEST_EQUAL(h.hasFlush(), false);
        h += Hand(4) + 8 + 12 + 16 + 17;
        TTEST_EQUAL(h.hasFlush(), false);
        h += 0;
        TTEST_EQUAL(h.hasFlush(), true);
    }

    TTEST_CASE("rankKey()")
    {
        TTEST_EQUAL((Hand(4) + Hand(8)).rankKey(), (Hand(9) + Hand(5)).rankKey());
        TTEST_EQUAL((Hand(4) + Hand(8)).rankKey() == (Hand(12) + Hand(5)).rankKey(), false);
    }

    void enumRankCombos(unsigned n, const Hand& h, unordered_set<uint32_t>& keys,
            unsigned s = 0, unsigned k = 0)
    {
        keys.insert(h.rankKey());
        if (n == 0)
            return;
        for (unsigned r = k; r < RANK_COUNT; ++r, s = 0) {
            if (s == 4)
                continue;
            enumRankCombos(n - 1, h + Hand(r * 4  + s), keys, s + 1, r);
        }
    }

    TTEST_CASE("rankKey() has no collisions")
    {
        unordered_set<uint32_t> keys;
        enumRankCombos(7, Hand::empty(), keys);
        TTEST_EQUAL(keys.size(), 76155u);
    }

    TTEST_CASE("flushKey()")
    {
        Hand h = Hand::empty() + 6 + 10 + 14 + 18 + 22 + 26 + 3;
        TTEST_EQUAL(h.flushKey(), 0x7eu);
    }
};

class HandEvaluatorTest : public ttest::TestBase
{
    HandEvaluator e;
    uint64_t counts[10]{};

    void enumerate(unsigned cardsLeft, const Hand& h = Hand::empty(), unsigned start = 0)
    {
        for (unsigned c = start; c < 52; ++c) {
            if (cardsLeft == 1)
                ++counts[e.evaluate(h + c) >> HAND_CATEGORY_SHIFT];
            else
                enumerate(cardsLeft - 1, h + c, c + 1);
        }
    }

    TTEST_BEFORE()
    {
        fill(begin(counts), end(counts), 0);
    }

    TTEST_CASE("0 cards")
    {
        TTEST_EQUAL(e.evaluate(Hand::empty()), HAND_CATEGORY_OFFSET + 1);
    }

    TTEST_CASE("enumerate 1 card hands")
    {
        uint64_t expected[10]{0, 52};
        enumerate(1);
        for (unsigned i = 0; i < 10; ++i)
            TTEST_EQUAL(counts[i], expected[i]);
    }

    TTEST_CASE("enumerate 2 cards hands")
    {
        uint64_t expected[10]{0, 1248, 78};
        enumerate(2);
        for (unsigned i = 0; i < 10; ++i)
            TTEST_EQUAL(counts[i], expected[i]);
    }

    TTEST_CASE("enumerate 3 cards hands")
    {
        uint64_t expected[10]{0, 18304, 3744, 0, 52};
        enumerate(3);
        for (unsigned i = 0; i < 10; ++i)
            TTEST_EQUAL(counts[i], expected[i]);
    }

    TTEST_CASE("enumerate 4 cards hands")
    {
        uint64_t expected[10]{0, 183040, 82368, 2808, 2496, 0, 0, 0, 13};
        enumerate(4);
        for (unsigned i = 0; i < 10; ++i)
            TTEST_EQUAL(counts[i], expected[i]);
    }

    TTEST_CASE("enumerate 5 cards hands")
    {
        uint64_t expected[10]{0, 1302540, 1098240, 123552, 54912, 10200, 5108, 3744, 624, 40};
        enumerate(5);
        for (unsigned i = 0; i < 10; ++i)
            TTEST_EQUAL(counts[i], expected[i]);
    }

    TTEST_CASE("enumerate 6 cards hands")
    {
        uint64_t expected[10]{0, 6612900, 9730740, 2532816, 732160, 361620, 205792, 165984, 14664, 1844};
        enumerate(6);
        for (unsigned i = 0; i < 10; ++i)
            TTEST_EQUAL(counts[i], expected[i]);
    }

    TTEST_CASE("enumerate 7 cards hands")
    {
        uint64_t expected[10]{0, 23294460, 58627800, 31433400, 6461620, 6180020, 4047644,
                3473184, 224848, 41584};
        enumerate(7);
        for (unsigned i = 0; i < 10; ++i)
            TTEST_EQUAL(counts[i], expected[i]);
    }
};

class EquityCalculatorTest : public ttest::TestBase
{
    EquityCalculator eq;

    struct TestCase
    {
        vector<string> ranges;
        string board, dead;
        vector<uint64_t> expectedResults;
    };

    vector<TestCase> TESTDATA = [&]{
        vector<TestCase> td;
        td.emplace_back(TestCase{{"AA", "KK"}, "", "",
                {0, 50371344, 10986372, 285228}});
        td.emplace_back(TestCase{ { "AK", "random"}, "2c3c", "",
                {0, 159167583, 108567320, 6233737}});
        td.emplace_back(TestCase{ {"random", "AA", "33"}, "2c3c8h", "6h",
                {0, 808395, 1681125, 20076, 12151512, 0, 0, 0}});
        td.emplace_back(TestCase{ {"random", "random", "AK"}, "4hAd3c4c7c", "6h",
                {0, 1461364, 1461364, 6386, 6760010, 42420, 42420, 108}});
        td.emplace_back(TestCase{ {"3d7d", "2h9h", "2c9c"}, "5d5h5c", "3s3c",
                {0, 183, 28, 0, 28, 0, 380, 201}});
        td.emplace_back(TestCase{ {"AA,KK", "KK,QQ", "QQ,AA" }, "", "",
                {0, 348272820, 119882736, 37653912, 303253020, 74015280, 1266624, 3904200}});
        return td;
    }(); // Workaround for MSVC2013's incomplete initializer list support.

    void enumTest(const TestCase& tc)
    {
        std::vector<CardRange> ranges2(tc.ranges.begin(), tc.ranges.end());
        if (!eq.start(ranges2, CardRange::getCardMask(tc.board), CardRange::getCardMask(tc.dead), true))
                throw ttest::TestException("Invalid hand ranges!");
        eq.wait();
        auto results = eq.getResults();
        for (unsigned i = 0; i < (1u << tc.ranges.size()); ++i)
            TTEST_EQUAL(results.winsByPlayerMask[i], tc.expectedResults[i]);
    }

    void monteCarloTest(const TestCase& tc)
    {
        double hands = accumulate(tc.expectedResults.begin(), tc.expectedResults.end(), 0.0);
        std::vector<CardRange> ranges2(tc.ranges.begin(), tc.ranges.end());
        bool timeout = false;
        auto callback = [&](const EquityCalculator::Results& r){
            double maxErr = 0;
            for (unsigned i = 0; i < (1u << tc.ranges.size()); ++i)
                maxErr = max(std::abs(tc.expectedResults[i] / hands - (double) r.winsByPlayerMask[i] / r.hands), maxErr);
            if (maxErr < 2e-4)
                eq.stop();
            if (r.time > 10) {
                timeout = true;
                eq.stop();
            }
        };
        if (!eq.start(ranges2, CardRange::getCardMask(tc.board), CardRange::getCardMask(tc.dead),
                false, 0.0, nullptr, 0.1))
            throw ttest::TestException("Invalid hand ranges!");
        eq.wait();
        if (timeout)
            throw ttest::TestException("Didn't converge to correct results in time!");
    }

    TTEST_BEFORE()
    {
        eq.setTimeLimit(0);
        eq.setHandLimit(0);
    }

    // TTEST_CASE("start() returns false when too many board cards")
    // {
    //     TTEST_EQUAL(eq.start({"random"}, CardRange::getCardMask("2c3c4c5c6c7c")), false);
    // }

    // TTEST_CASE("start() returns false when too many players")
    // {
    //     TTEST_EQUAL(eq.start({"AA", "KK", "QQ", "JJ", "TT", "99", "88"}), false);
    // }

    // TTEST_CASE("start() returns false when too few cards left in the deck")
    // {
    //     // 2*2 + (4 + 1) + 43 = 52
    //     TTEST_EQUAL(eq.start({"33", "33"}, 0xf, 0xffffffffffe00), true);
    //     eq.stop();
    //     eq.wait();
    //     // 2*2 + (4 + 1) + 44 = 53
    //     TTEST_EQUAL(eq.start({"33", "33"}, 0xf, 0xfffffffffff00), false);
    // }

    // TTEST_CASE("start() returns false when hand range is empty after card removal")
    // {
    //     TTEST_EQUAL(eq.start({"random", ""}), false);
    //     std::vector<CardRange> ranges = { CardRange("AA"), CardRange("22") };
    //     TTEST_EQUAL(eq.start(ranges, CardRange::getCardMask("AsAh"), CardRange::getCardMask("Ac")), false);
    // }

    // TTEST_CASE("start() returns false when no feasible combination of holecards")
    // {
    //     TTEST_EQUAL(eq.start({"AA", "AK"}, CardRange::getCardMask("As"), CardRange::getCardMask("Ah")), false);
    // }

    // TTEST_CASE("time limit")
    // {
    //     eq.setTimeLimit(0.5);
    //     auto callback = [&](const EquityCalculator::Results& r){
    //         if (r.time >= 2)
    //             eq.stop();
    //     };
    //     std::vector<CardRange> ranges = { CardRange("random"), CardRange("random") };
    //     eq.start(ranges, 0, 0, false, 0.0, nullptr, 1.0);
    //     eq.wait();
    //     auto r = eq.getResults();
    //     TTEST_EQUAL(r.time >= 0.45 && r.time <= 0.55, true);
    // }

    // TTEST_CASE("hand limit")  
    // {
    //     eq.setHandLimit(3000000);
    //     auto callback = [&](const EquityCalculator::Results& r){
    //         if (r.time >= 2)
    //             eq.stop();
    //     };
    //     std::vector<CardRange> ranges = { CardRange("random"), CardRange("random") };
    //     eq.start(ranges, 0, 0, false, 0.0, nullptr, 1.0);
    //     eq.wait();
    //     auto r = eq.getResults();
    //     TTEST_EQUAL(r.hands >= 3000000 && r.hands <= 3000000 + 16 * 0x1000, true);
    // }

// 以下为增加的调试CASE：
    // 没带权重的测试案例:
    // TTEST_CASE("PLAY1 vs PLAY2 with flop AhKd2c, enumeration and monte carlo") 
    // {
    // std::vector<CardRange> ranges = {
    //     CardRange("45s,22,35,QQ+,AK"), 
    //     CardRange("KK,JQ,89,TA")
    // };
    // uint64_t board = CardRange::getCardMask("AhKd2c");
    // uint64_t dead = 0;

    // // Enumeration
    // EquityCalculator eq_enum;
    // eq_enum.start(ranges, board, dead, true);  // true = enumeration
    // eq_enum.wait();
    // auto r_enum = eq_enum.getResults();

    // std::cout << "\n[Enumeration] PLAY1 equity: " << r_enum.equity[0]
    //           << " PLAY2 equity: " << r_enum.equity[1] << std::endl;
    // std::cout << "[Enumeration] PLAY1 wins: " << r_enum.winsByPlayerMask[1]
    //           << " PLAY2 wins: " << r_enum.winsByPlayerMask[2] << ","
    //           << " Ties: " << r_enum.winsByPlayerMask[3]
    //           << " Total hands: " << r_enum.hands << std::endl;

    // // Monte Carlo
    // EquityCalculator eq_mc;
    // eq_mc.start(ranges, board, dead, false, 0.01); // false = monte carlo
    // eq_mc.wait();
    // auto r_mc = eq_mc.getResults();

    // std::cout << "[Monte Carlo] PLAY1 equity: " << r_mc.equity[0]
    //           << " PLAY2 equity: " << r_mc.equity[1] << std::endl;
    // std::cout << "[Monte Carlo] PLAY1 wins: " << r_mc.winsByPlayerMask[1]
    //           << " PLAY2 wins: " << r_mc.winsByPlayerMask[2]
    //           << " Ties: " << r_mc.winsByPlayerMask[3]
    //           << " Total hands: " << r_mc.hands << std::endl
    //           << " Time: " << r_mc.time << " seconds" << std::endl
    //           <<" "<<endl;
    // }

    // 带权重测试用例
    TTEST_CASE("Two or Three Players, weight enumeration") 
    {
    // 解析公共牌和死牌
    uint64_t board = CardRange::getCardMask(w_board);
    uint64_t dead = 0;
    
    // 将board和dead转换为uint8_t向量
    std::vector<uint8_t> boardCards;
    std::vector<uint8_t> deadCards;
    for (unsigned i = 0; i < 52; ++i) {
        if (board & (1ull << i)) {
            boardCards.push_back(i);
        }
    }
    
    // 构造WeightedCardRange
    std::vector<WeightedCardRange> ranges_weighted;
    ranges_weighted.reserve(2);
    ranges_weighted.emplace_back(range0, true, false);
    ranges_weighted.emplace_back(range1, true, false);
    if (!range2.empty()){
        ranges_weighted.emplace_back(range2, true, false);
    }
    
    // 冲突检验：检测手牌范围中与公共牌冲突的手牌
    // std::cout << "测试冲突检测：公共牌包含" << w_board << std::endl;
    std::vector<int> conflictCounts(ranges_weighted.size(), 0);
    std::vector<int> validCounts(ranges_weighted.size(), 0);
    for (size_t i = 0; i < ranges_weighted.size(); ++i) {
        // std::cout << "玩家" << i << "原始手牌组合数: " << ranges_weighted[i].getWeightedCombos().size() << std::endl;
        // 检查是否有与公共牌冲突的手牌
        const auto& combos = ranges_weighted[i].getWeightedCombos();
        for (const auto& [hand, weight] : combos) {
            // 获取手牌掩码
            const auto& cardArray = hand;
            uint64_t handMask = (1ull << cardArray[0]) | (1ull << cardArray[1]);
            // 检查与公共牌的冲突
            if (handMask & board) {
                conflictCounts[i]++;
            } else {
                validCounts[i]++;
            }
        }
        // std::cout << "玩家" << i << "与公共牌冲突的手牌组合数: " << conflictCounts[i] << std::endl;
        // std::cout << "玩家" << i << "有效手牌组合数: " << validCounts[i] << std::endl;
    }

    // 加权全枚举
    EquityCalculator eq_weighted_enum;
    eq_weighted_enum.setEnumerateAll(true); // 启用全枚举模式
    eq_weighted_enum.start_v2(ranges_weighted, board, dead);
    
    eq_weighted_enum.wait();
    auto r_enum = eq_weighted_enum.getResults();

    std::cout << "\ntotal_eq:" << std::fixed << std::setprecision(6) << r_enum.equity[0]
              << "," << std::fixed << std::setprecision(6) << r_enum.equity[1];
    if (!range2.empty()){
        std::cout << "," << std::fixed << std::setprecision(6) << r_enum.equity[2];
    }
    // 获取牌型胜率（枚举模式）
    std::vector<std::unordered_map<std::string, double>> typeEquities = eq_weighted_enum.getTypeEquities();
    // 创建JSON对象并填充胜率数据
    json equityJson;
    for (unsigned i = 0; i < typeEquities.size(); ++i) {
        std::string playerKey = "PLAY" + std::to_string(i);
        json handArray = json::array();
        
        // 创建临时集合存储已处理的手牌，避免重复添加
        std::unordered_set<std::string> processedHands;
        
        // 先处理typeEquities中的手牌
        for (const auto& pair : typeEquities[i]) {
            const std::string& handStr = pair.first;
            double equity = pair.second;
            
            // 检查手牌是否与公共牌冲突
            std::array<uint8_t, 2> hand = stringToHand(handStr);
            uint64_t handMask = (1ull << hand[0]) | (1ull << hand[1]);
            
            if (!(handMask & board)) {  // 只添加非冲突手牌
                std::ostringstream oss;
                oss << handStr << ":" << std::fixed << std::setprecision(6) << equity;
                handArray.push_back(oss.str());
                processedHands.insert(handStr);
            }
        }
        
        // 补充原始手牌范围中的非冲突手牌，但不在typeEquities中的情况
        const auto& combos = ranges_weighted[i].getWeightedCombos();
        for (const auto& combo : combos) {
            std::string handStr = CardRange::handToString(combo.first);
            
            // 如果这手牌已经处理过，则跳过
            if (processedHands.find(handStr) != processedHands.end()) {
                continue;
            }
            
            // 再次检查与公共牌的冲突（使用与CardRange::getCardMask一致的逻辑）
            uint64_t handMask = (1ull << combo.first[0]) | (1ull << combo.first[1]);
            
            if (!(handMask & board)) {  // 只添加非冲突手牌（无论胜率是否为0）
                
                std::array<uint8_t, 2> parsedHand = stringToHand(handStr);
                uint64_t parsedHandMask = (1ull << parsedHand[0]) | (1ull << parsedHand[1]);
                
                if (!(parsedHandMask & board)) {  // 双重验证确保不包含公共牌
                    std::ostringstream oss;
                    double actualEquity = 0.0;
                    auto equityIt = typeEquities[i].find(handStr);
                    if (equityIt != typeEquities[i].end()) {
                        actualEquity = equityIt->second;
                    } else {
                        // 花色同构处理：将手牌转换为规范形式后查找
                        if (handStr.size() == 4) {
                            // 提取点数和花色信息
                            char rank1 = toupper(handStr[0]);
                            char rank2 = toupper(handStr[2]);
                            char suit1 = handStr[1];
                            char suit2 = handStr[3];
                            
                            // 规范化点数顺序（点数大的在前）
                            if ((rank1 == 'T' && rank2 != 'T') || 
                                (rank1 == 'J' && (rank2 == 'Q' || rank2 == 'K' || rank2 == 'A')) || 
                                (rank1 == 'Q' && (rank2 == 'K' || rank2 == 'A')) || 
                                (rank1 == 'K' && rank2 == 'A') || 
                                (rank1 >= '2' && rank1 <= '9' && 
                                 ((rank2 >= '2' && rank2 <= '9' && rank1 < rank2) || 
                                  (rank2 == 'T' || rank2 == 'J' || rank2 == 'Q' || rank2 == 'K' || rank2 == 'A')))) {
                                std::swap(rank1, rank2);
                                std::swap(suit1, suit2);
                            }
                            
                            // 在typeEquities中查找任何具有相同点数组合的手牌
                            for (const auto& pair : typeEquities[i]) {
                                if (pair.first.size() == 4) {
                                    char pairRank1 = toupper(pair.first[0]);
                                    char pairRank2 = toupper(pair.first[2]);
                                    
                                    // 规范化pair的点数顺序
                                    if ((pairRank1 == 'T' && pairRank2 != 'T') || 
                                        (pairRank1 == 'J' && (pairRank2 == 'Q' || pairRank2 == 'K' || pairRank2 == 'A')) || 
                                        (pairRank1 == 'Q' && (pairRank2 == 'K' || pairRank2 == 'A')) || 
                                        (pairRank1 == 'K' && pairRank2 == 'A') || 
                                        (pairRank1 >= '2' && pairRank1 <= '9' && 
                                         ((pairRank2 >= '2' && pairRank2 <= '9' && pairRank1 < pairRank2) || 
                                          (pairRank2 == 'T' || pairRank2 == 'J' || pairRank2 == 'Q' || pairRank2 == 'K' || pairRank2 == 'A')))) {
                                        std::swap(pairRank1, pairRank2);
                                    }
                                    
                                    // 如果点数组合相同，则使用该胜率
                                    if (pairRank1 == rank1 && pairRank2 == rank2) {
                                        actualEquity = pair.second;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    // 统一使用固定小数点格式显示所有值
                    oss << handStr << ":";
                    oss << std::fixed << std::setprecision(6) << actualEquity;
                    handArray.push_back(oss.str());
                }
            }
        }
        
        equityJson[playerKey] = handArray;
    }
    
    std::cout << "\nresults:" << equityJson << std::endl;
    // std::cout << "[Weighted Enumeration] Total time: " << fixed << setprecision(6) << r_enum.time << " seconds" << std::endl;
    
    // 加权蒙特卡洛
    // EquityCalculator eq_weighted;
    // eq_weighted.start_v2(ranges_weighted, board, dead);  // 直接调用加权蒙特卡洛接口
    // eq_weighted.wait();
    // auto r_weighted = eq_weighted.getResults();

    // double total_weighted=r_weighted.totalAllSum;
    // double ties=r_weighted.weightedTies;
    // // 获取总胜率
    // std::cout << "\ntotal_eq:" << std::fixed << std::setprecision(6) << r_weighted.equity[0]
    //       << "," << std::fixed << std::setprecision(6) << r_weighted.equity[1];
    //       if (!range2.empty()){
    //         std::cout << "," << std::fixed << std::setprecision(6) << r_weighted.equity[2];
    //       }
    //       std::cout << std::endl;

    // // 输出加权值而非场次，并显示总权重
    // std::cout << "[Weighted Monte Carlo] PLAY0 weighted wins: " << std::fixed << std::setprecision(6) << r_weighted.wins[0]-(ties/2)
    //       << " PLAY1 weighted wins: " << std::fixed << std::setprecision(6) << r_weighted.wins[1]-(ties/2)
    //       << " Weighted ties: " << std::fixed << std::setprecision(6) << ties 
    //       << " Total weight: " << std::fixed << std::setprecision(6) << total_weighted<< std::endl;
    
    // // 获取牌型胜率（加权蒙特卡洛）
    // std::vector<std::unordered_map<std::string, double>> typeEquities = eq_weighted.getTypeEquities();
    // // 创建JSON对象并填充胜率数据
    // json equityJson;
    // for (unsigned i = 0; i < typeEquities.size(); ++i) {
    //     std::string playerKey = "PLAY" + std::to_string(i);
    //     json handArray = json::array();
    //     for (const auto& pair : typeEquities[i]) {
    //     // 格式化手牌和胜率为字符串
    //         std::ostringstream oss;
    //         oss << pair.first << ":" << std::fixed << std::setprecision(6) << pair.second;
    //         handArray.push_back(oss.str());
    //     }
    //     equityJson[playerKey] = handArray;
    // }
    // // 输出JSON
    // std::cout << "\nresults:" << equityJson<< std::endl;
    // std::cout << "[Weighted Monte Carlo] Total time: " << fixed << setprecision(6) << r_weighted.time << " seconds" << std::endl;
    // // // 输出加权值而非场次，并显示总权重
    // // std::cout << "[Weighted Monte Carlo] PLAY0 weighted wins: " << std::fixed << std::setprecision(6) << r_weighted.wins[0]-(ties/2)
    // //       << " PLAY1 weighted wins: " << std::fixed << std::setprecision(6) << r_weighted.wins[1]-(ties/2)
    // //       << " Weighted ties: " << std::fixed << std::setprecision(6) << ties 
    // //       << " Total weight: " << std::fixed << std::setprecision(6) << total_weighted<< std::endl;
    
    // // 获取牌型胜率（加权蒙特卡洛）
    // std::vector<std::unordered_map<std::string, double>> typeEquities = eq_weighted.getTypeEquities();
    // // 创建JSON对象并填充胜率数据
    // json equityJson;
    // for (unsigned i = 0; i < typeEquities.size(); ++i) {
    //     std::string playerKey = "PLAY" + std::to_string(i);
    //     json handArray = json::array();
    //     for (const auto& pair : typeEquities[i]) {
    //     // 格式化手牌和胜率为字符串
    //         std::ostringstream oss;
    //         oss << pair.first << ": " << std::fixed << std::setprecision(6) << pair.second;
    //         handArray.push_back(oss.str());
    //     }
    //     equityJson[playerKey] = handArray;
    // }
    // // 输出JSON
    // std::cout << "\nresults:" << equityJson<< std::endl;
    // // std::cout << "[Weighted Monte Carlo] Total time: " << fixed << setprecision(6) << r_weighted.time << " seconds" << std::endl;
    
    }
    
    // TTEST_CASE("test 1 - enumeration") { enumTest(TESTDATA[0]); }
    // TTEST_CASE("test 1 - monte carlo") { monteCarloTest(TESTDATA[0]); }
    // TTEST_CASE("test 2 - enumeration") { enumTest(TESTDATA[1]); }
    // TTEST_CASE("test 2 - monte carlo") { monteCarloTest(TESTDATA[1]); }
    // TTEST_CASE("test 3 - enumeration") { enumTest(TESTDATA[2]); }
    // TTEST_CASE("test 3 - monte carlo") { monteCarloTest(TESTDATA[2]); }
    // TTEST_CASE("test 4 - enumeration") { enumTest(TESTDATA[3]); }
    // TTEST_CASE("test 4 - monte carlo") { monteCarloTest(TESTDATA[3]); }
    // TTEST_CASE("test 5 - enumeration") { enumTest(TESTDATA[4]); }
    // TTEST_CASE("test 5 - monte carlo") { monteCarloTest(TESTDATA[4]); }
    // TTEST_CASE("test 6 - enumeration") { enumTest(TESTDATA[5]); }
    // TTEST_CASE("test 6 - monte carlo") { monteCarloTest(TESTDATA[5]); }
};

void printBuildInfo()
{
    cout << "=== Build information ===" << endl;
    cout << "" << (sizeof(void*) * 8) << "-bit" << endl;
    #if OMP_x64
    cout << "x64" << endl;
    #endif
    #if OMP_SSE2
    cout << "SSE2" << endl;
    #else
    cout << "No SSE" << endl;
    #endif
    #if OMP_SSE4
    cout << "SSE4" << endl;
    #endif
}

void benchmark();

int main(int argc, char* argv[])
{
    // 解析命令行参数
    if (argc == 4) {
        w_board = argv[1];
        range0 = argv[2];
        range1 = argv[3];
        range2 = "";
    }else if(argc == 5){
        w_board = argv[1];
        range0 = argv[2];
        range1 = argv[3];
        range2 = argv[4];
    } else {
        std::cerr << "Parameter error: 3 or 4 input argc required (board range0 range1 range2)" << std::endl;
        return -1;
    }

    // printBuildInfo();
    // cout << endl << "=== Tests ===" << endl;
    // cout << "Util:" << endl;
    // UtilTest().run();
    // cout << "Hand:" << endl;
    // HandTest().run();
    // cout << "HandEvaluator:" << endl;
    // HandEvaluatorTest().run();
    cout << "EquityCalculator:" << endl;
    EquityCalculatorTest().run();

    // cout << endl << endl << "=== Benchmarks ===" << endl;
    // void benchmark();
    // benchmark();
    // cout << endl << "Done." << endl;

    return 0;
}

// 辅助函数：将手牌字符串转换为卡牌ID数组
std::array<uint8_t, 2> stringToHand(const std::string& handStr) {
    // 确保输入字符串格式正确
    if (handStr.length() != 4) {
        throw std::invalid_argument("Invalid hand string format");
    }
    
    uint8_t card1 = 0, card2 = 0;
    
    // 解析第一张牌
    char rank1 = handStr[0];
    char suit1 = handStr[1];
    switch(tolower(rank1)) {
        case 'a': card1 |= 12 << 2; break;
        case 'k': card1 |= 11 << 2; break;
        case 'q': card1 |= 10 << 2; break;
        case 'j': card1 |= 9 << 2; break;
        case 't': card1 |= 8 << 2; break;
        case '9': card1 |= 7 << 2; break;
        case '8': card1 |= 6 << 2; break;
        case '7': card1 |= 5 << 2; break;
        case '6': card1 |= 4 << 2; break;
        case '5': card1 |= 3 << 2; break;
        case '4': card1 |= 2 << 2; break;
        case '3': card1 |= 1 << 2; break;
        case '2': card1 |= 0 << 2; break;
    }
    switch(tolower(suit1)) {
        case 's': card1 |= 0; break;
        case 'h': card1 |= 1; break;
        case 'c': card1 |= 2; break;
        case 'd': card1 |= 3; break;
    }
    
    // 解析第二张牌
    char rank2 = handStr[2];
    char suit2 = handStr[3];
    switch(tolower(rank2)) {
        case 'a': card2 |= 12 << 2; break;
        case 'k': card2 |= 11 << 2; break;
        case 'q': card2 |= 10 << 2; break;
        case 'j': card2 |= 9 << 2; break;
        case 't': card2 |= 8 << 2; break;
        case '9': card2 |= 7 << 2; break;
        case '8': card2 |= 6 << 2; break;
        case '7': card2 |= 5 << 2; break;
        case '6': card2 |= 4 << 2; break;
        case '5': card2 |= 3 << 2; break;
        case '4': card2 |= 2 << 2; break;
        case '3': card2 |= 1 << 2; break;
        case '2': card2 |= 0 << 2; break;
    }
    switch(tolower(suit2)) {
        case 's': card2 |= 0; break;
        case 'h': card2 |= 1; break;
        case 'c': card2 |= 2; break;
        case 'd': card2 |= 3; break;
    }
    
    // 确保卡牌顺序正确（点数大的在前，如果点数相同则花色小的在前）
    if ((card1 >> 2) < (card2 >> 2) || 
        ((card1 >> 2) == (card2 >> 2) && (card1 & 3) > (card2 & 3))) {
        std::swap(card1, card2);
    }
    
    return {card1, card2};
}

// 声明外部函数，用于handToString
extern std::string handToString(const std::array<uint8_t, 2>& hand);

